#include "bottomcontrolbox.h"
#include <QDebug>
#include <QHostAddress>
#include <QtEndian>
#include <QNetworkDatagram>
#include <QTime>

// 构造函数
BottomControlBox::BottomControlBox(QObject *parent)
    : QObject(parent)
    , m_heartbeat(0)
    , m_isShowHeart(true)
{
    memset(&feedbackData, 0, sizeof(FeedbackDataStruct));
}

// 析构函数
BottomControlBox::~BottomControlBox()
{
    if(m_udpSocket) {
        delete m_udpSocket;
    }
}

// 初始化整体
void BottomControlBox::init()
{
    // 初始化UDP Socket（绑定航控IP和端口：192.168.11.45:8001）
    m_udpSocket = new QUdpSocket(this);
    if (!m_udpSocket->bind(QHostAddress(m_localIp), m_localPort)) {
        emit sigError(QString("[发送端] UDP绑定失败：%1").arg(m_udpSocket->errorString()));
        return;
    }

    emit sigSuccess(QString("[发送端] 已绑定：%1:%2").arg(m_localIp).arg(QString::number(m_localPort)));

    // 信号槽连接：修正类名作用域
    connect(m_udpSocket, &QUdpSocket::readyRead, this, &BottomControlBox::onReceive);

    // 初始化一遍发送结构体的值
    initSendCmd();

    //初始化心跳包帧结构固定值
    m_frame.frameHeader = 0xFE;
    m_frame.reserved1 = 0x00;
    m_frame.sourceNode = m_srcNode;
    m_frame.destNode = 0xBB;
    m_frame.cmdType = 0xAC;
    m_frame.ackFlag = 0x00;
    m_frame.reserved2 = 0x0000;
    m_frame.frameTail = 0xFF;

    // 计算数据长度(除去帧头、帧尾、校验码和数据长度本身)
    m_frame.dataLength = 0x09;

    m_timer = new QTimer(this);
    m_sequence = 0;

    // 信号槽连接：修正类名作用域
    connect(m_timer, &QTimer::timeout, this, &BottomControlBox::onSendHeartbeat);

    //开始心跳发送（测试）
    startSending();

    // **********初始化超时检查定时器（100ms扫描一次，避免频繁占用资源）**********
    m_timeoutTimer = new QTimer(this);
    m_timeoutTimer->setInterval(100);  // 扫描间隔：ms
    connect(m_timeoutTimer, &QTimer::timeout, this, &BottomControlBox::onCheckTimeout);
    m_timeoutTimer->start();  // 启动超时扫描
}

void BottomControlBox::setNetConfig(QString localIp, quint16 localPort, QString dstIp, quint16 dstPort)
{
    m_localIp = localIp;
    m_localPort = localPort;
    m_dstIp = dstIp;
    m_dstPort = dstPort;
}

void BottomControlBox::setNode(quint8 srcNode, quint8 dstNode)
{
    m_srcNode = srcNode;
    m_dstNode = dstNode;
}

// 开始定时发送心跳
void BottomControlBox::startSending()
{
    m_timer->start(1000);
}

// 停止定时发送心跳
void BottomControlBox::stopSending()
{
    m_timer->stop();
}

// 是否显示心跳发送和接收信息
void BottomControlBox::showHeartDebug(bool isShow)
{
    m_isShowHeart = isShow;
}

// 左柴油机启停设置
bool BottomControlBox::leftDieselEngineStartStop(uint8 setCmd)
{
    //先赋值，再发送
    m_sendCmd.leftEngineStartStop = setCmd;

    //更改指令序号
    m_sendCmd.leftEngineStartStopSeq = (m_sendCmd.leftEngineStartStopSeq >= 255) ? 1 : (m_sendCmd.leftEngineStartStopSeq + 1);

    //更改心跳值（小端发送）
    m_sendCmd.heartbeat = qToLittleEndian((m_heartbeat >= 65535) ? 0 : (m_heartbeat + 1));

    //发送所有指令
    if(!sendCmd()) {
        emit sigError("发送左柴油机启停设置指令失败");
        return false;
    } else {
        CmdKey key(CmdType::LeftDieselStartStop, m_sendCmd.leftEngineStartStopSeq);
        m_pendingCmds.insert(key, QTime::currentTime());  // 存储发送时间
        emit sigSuccess(QString("发送左柴油机启停设置指令成功,序号为%1").arg(m_sendCmd.leftEngineStartStopSeq));
        return true;
    }
}

// 左喷泵挡位设置
bool BottomControlBox::leftSprayPumpGear(uint8 setCmd)
{
    //先赋值，再发送
    m_sendCmd.leftPumpGear = setCmd;

    //更改指令序号
    m_sendCmd.leftPumpGearSeq = (m_sendCmd.leftPumpGearSeq >= 255) ? 1 : (m_sendCmd.leftPumpGearSeq + 1);

    //更改心跳值（小端发送）
    m_sendCmd.heartbeat = qToLittleEndian((m_heartbeat >= 65535) ? 0 : (m_heartbeat + 1));

    //发送所有指令
    if(!sendCmd()) {
        emit sigError("发送左喷泵挡位设置指令失败");
        return false;
    } else {
        CmdKey key(CmdType::LeftPumpGear, m_sendCmd.leftPumpGearSeq);
        m_pendingCmds.insert(key, QTime::currentTime());  // 存储发送时间
        emit sigSuccess(QString("发送左喷泵挡位设置指令成功,序号为%1").arg(m_sendCmd.leftPumpGearSeq));
        return true;
    }
}

// 左喷泵油门设置
bool BottomControlBox::leftSprayPumpThrottle(uint16 setCmd)
{
    //先赋值，再发送
    m_sendCmd.leftPumpThrottle = qToLittleEndian(setCmd);

    //更改指令序号
    m_sendCmd.leftPumpThrottleSeq = (m_sendCmd.leftPumpThrottleSeq >= 255) ? 1 : (m_sendCmd.leftPumpThrottleSeq + 1);

    //更改心跳值（小端发送）
    m_sendCmd.heartbeat = qToLittleEndian((m_heartbeat >= 65535) ? 0 : (m_heartbeat + 1));

    //发送所有指令
    if(!sendCmd()) {
        emit sigError("发送左喷泵油门设置指令失败");
        return false;
    } else {
        CmdKey key(CmdType::LeftPumpThrottle, m_sendCmd.leftPumpThrottleSeq);  // 原代码用错序号变量，已修正为leftPumpThrottleSeq
        m_pendingCmds.insert(key, QTime::currentTime());  // 存储发送时间
        emit sigSuccess(QString("发送左喷泵油门设置指令成功,序号为%1").arg(m_sendCmd.leftPumpThrottleSeq));  // 同步修正序号变量
        return true;
    }
}

// 左喷泵舵角设置
bool BottomControlBox::leftSprayPumpRudderAngle(int setCmd)
{
    //先赋值，再发送
    m_sendCmd.leftPumpRudderAngle = qToLittleEndian(setCmd);

    //更改指令序号
    m_sendCmd.leftPumpRudderAngleSeq = (m_sendCmd.leftPumpRudderAngleSeq >= 255) ? 1 : (m_sendCmd.leftPumpRudderAngleSeq + 1);

    //更改心跳值（小端发送）
    m_sendCmd.heartbeat = qToLittleEndian((m_heartbeat >= 65535) ? 0 : (m_heartbeat + 1));

    //发送所有指令
    if(!sendCmd()) {
        emit sigError("发送左喷泵舵角设置指令失败");
        return false;
    } else {
        CmdKey key(CmdType::LeftPumpRudderAngle, m_sendCmd.leftPumpRudderAngleSeq);
        m_pendingCmds.insert(key, QTime::currentTime());  // 存储发送时间
        emit sigSuccess(QString("发送左喷泵舵角设置指令成功,序号为%1").arg(m_sendCmd.leftPumpRudderAngleSeq));
        return true;
    }
}

// 右柴油机启停设置
bool BottomControlBox::rightDieselEngineStartStop(uint8 setCmd)
{
    //先赋值，再发送
    m_sendCmd.rightEngineStartStop = setCmd;

    //更改指令序号
    m_sendCmd.rightEngineStartStopSeq = (m_sendCmd.rightEngineStartStopSeq >= 255) ? 1 : (m_sendCmd.rightEngineStartStopSeq + 1);

    //更改心跳值（小端发送）
    m_sendCmd.heartbeat = qToLittleEndian((m_heartbeat >= 65535) ? 0 : (m_heartbeat + 1));

    //发送所有指令
    if(!sendCmd()) {
        emit sigError("发送右柴油机启停设置指令失败");
        return false;
    } else {
        CmdKey key(CmdType::RightDieselStartStop, m_sendCmd.rightEngineStartStopSeq);
        m_pendingCmds.insert(key, QTime::currentTime());  // 存储发送时间
        emit sigSuccess(QString("发送右柴油机启停设置指令成功,序号为%1").arg(m_sendCmd.rightEngineStartStopSeq));
        return true;
    }
}

// 右喷泵挡位设置
bool BottomControlBox::rightSprayPumpGear(uint8 setCmd)
{
    //先赋值，再发送
    m_sendCmd.rightPumpGear = setCmd;

    //更改指令序号
    m_sendCmd.rightPumpGearSeq = (m_sendCmd.rightPumpGearSeq >= 255) ? 1 : (m_sendCmd.rightPumpGearSeq + 1);

    //更改心跳值（小端发送）
    m_sendCmd.heartbeat = qToLittleEndian((m_heartbeat >= 65535) ? 0 : (m_heartbeat + 1));

    //发送所有指令
    if(!sendCmd()) {
        emit sigError("发送右喷泵挡位设置指令失败");
        return false;
    } else {
        CmdKey key(CmdType::RightPumpGear, m_sendCmd.rightPumpGearSeq);
        m_pendingCmds.insert(key, QTime::currentTime());  // 存储发送时间
        emit sigSuccess(QString("发送右喷泵挡位设置指令成功，序号为%1").arg(m_sendCmd.rightPumpGearSeq));
        return true;
    }
}

// 右喷泵油门设置
bool BottomControlBox::rightSprayPumpThrottle(uint16 setCmd)
{
    //先赋值，再发送
    m_sendCmd.rightPumpThrottle = qToLittleEndian(setCmd);

    //更改指令序号
    m_sendCmd.rightPumpThrottleSeq = (m_sendCmd.rightPumpThrottleSeq >= 255) ? 1 : (m_sendCmd.rightPumpThrottleSeq + 1);

    //更改心跳值（小端发送）
    m_sendCmd.heartbeat = qToLittleEndian((m_heartbeat >= 65535) ? 0 : (m_heartbeat + 1));

    //发送所有指令
    if(!sendCmd()) {
        emit sigError("发送右喷泵油门设置指令失败");
        return false;
    } else {
        CmdKey key(CmdType::RightPumpThrottle, m_sendCmd.rightPumpThrottleSeq);  // 原代码用错序号变量，已修正为rightPumpThrottleSeq
        m_pendingCmds.insert(key, QTime::currentTime());  // 存储发送时间
        emit sigSuccess(QString("发送右喷泵油门设置指令成功,序号为%1").arg(m_sendCmd.rightPumpThrottleSeq));  // 同步修正序号变量
        return true;
    }
}

// 右喷泵舵角设置
bool BottomControlBox::rightSprayPumpRudderAngle(int setCmd)
{
    //先赋值，再发送
    m_sendCmd.rightPumpRudderAngle = qToLittleEndian(setCmd);

    //更改指令序号
    m_sendCmd.rightPumpRudderAngleSeq = (m_sendCmd.rightPumpRudderAngleSeq >= 255) ? 1 : (m_sendCmd.rightPumpRudderAngleSeq + 1);

    //更改心跳值（小端发送）
    m_sendCmd.heartbeat = qToLittleEndian((m_heartbeat >= 65535) ? 0 : (m_heartbeat + 1));

    //发送所有指令
    if(!sendCmd()) {
        emit sigError("发送右喷泵舵角设置指令失败");
        return false;
    } else {
        CmdKey key(CmdType::RightPumpRudderAngle, m_sendCmd.rightPumpRudderAngleSeq);
        m_pendingCmds.insert(key, QTime::currentTime());  // 存储发送时间
        emit sigSuccess(QString("发送右喷泵舵角设置指令成功,序号为%1").arg(m_sendCmd.rightPumpRudderAngleSeq));
        return true;
    }
}

// 初始化发送结构体函数
void BottomControlBox::initSendCmd()
{
    // 1. 初始化控制指令
    m_sendCmd.header = 0xFE;                          // 帧头固定
    m_sendCmd.reserve0 = 0x00;                        //预留字节
    m_sendCmd.dataLen = qToLittleEndian((uint16)41);  // 数据长度（小端）
    m_sendCmd.srcNode = m_srcNode;                      // 源节点：航控
    m_sendCmd.destNode = m_dstNode;                     // 目标节点：底层
    m_sendCmd.cmdType = 0x01;                         // 指令类型：控制指令
    m_sendCmd.confirmFlag = 0x01;                     // 确认标志：需要确认
    m_sendCmd.heartbeat = qToLittleEndian(m_heartbeat);// 心跳（小端）
    m_sendCmd.reserve1 = qToLittleEndian((uint16)0);  // 预留字段清零
    m_sendCmd.tail = 0xFF;                            // 帧尾固定

    // 2. 指令序号初始化，此处设置为全0（使用时是对应的功能0-255循环，255后跳1）
    m_sendCmd.leftEngineStartStopSeq = 0;
    m_sendCmd.leftPumpGearSeq = 0;
    m_sendCmd.leftPumpThrottleSeq = 0;
    m_sendCmd.leftPumpRudderAngleSeq = 0;
    m_sendCmd.rightEngineStartStopSeq = 0;
    m_sendCmd.rightPumpGearSeq = 0;
    m_sendCmd.rightPumpThrottleSeq = 0;
    m_sendCmd.rightPumpRudderAngleSeq = 0;

    // 3. 填充控制参数
    m_sendCmd.leftEngineStartStop = 0x00;             // 左柴油机：默认状态
    m_sendCmd.leftPumpGear = 0x00;                    // 左喷泵：空挡
    m_sendCmd.leftPumpThrottle = qToLittleEndian((uint16)0); // 左油门：0‰（原注释50%与值不符，保持原值）
    m_sendCmd.leftPumpRudderAngle = qToLittleEndian((int16)0); // 左舵角：0°
    m_sendCmd.leftReserve3 = 0x00;
    m_sendCmd.leftReserve4 = 0x00;

    m_sendCmd.rightEngineStartStop = 0x00;            // 右柴油机：默认状态
    m_sendCmd.rightPumpGear = 0x00;                   // 右喷泵：空挡
    m_sendCmd.rightPumpThrottle = qToLittleEndian((uint16)0); // 右油门：0‰
    m_sendCmd.rightPumpRudderAngle = qToLittleEndian((int16)0); // 右舵角：0°
    m_sendCmd.rightReserve3 = 0x00;
    m_sendCmd.rightReserve4 = 0x00;

    // 4. 预留字段清零
    m_sendCmd.reserve2 = qToLittleEndian((uint16)0);
    m_sendCmd.reserve3 = qToLittleEndian((uint16)0);
    m_sendCmd.reserve4 = qToLittleEndian((uint16)0);
    m_sendCmd.reserve5 = qToLittleEndian((uint16)0);

    // 5. 计算CRC16校验（排除帧头、帧尾、校验码）
    QByteArray crcBuffer;
    QDataStream crcStream(&crcBuffer, QIODevice::WriteOnly);
    crcStream.setByteOrder(QDataStream::LittleEndian);
    // 写入需校验的字段（dataLen ~ reserve5）
    crcStream << m_sendCmd.dataLen << m_sendCmd.srcNode << m_sendCmd.destNode << m_sendCmd.cmdType
              << m_sendCmd.confirmFlag << m_sendCmd.heartbeat << m_sendCmd.reserve1
              << m_sendCmd.leftEngineStartStopSeq << m_sendCmd.leftEngineStartStop
              << m_sendCmd.leftPumpGearSeq << m_sendCmd.leftPumpGear << m_sendCmd.leftReserve3
              << m_sendCmd.leftPumpThrottleSeq << m_sendCmd.leftPumpThrottle << m_sendCmd.leftReserve4
              << m_sendCmd.leftPumpRudderAngleSeq << m_sendCmd.leftPumpRudderAngle
              << m_sendCmd.rightEngineStartStopSeq << m_sendCmd.rightEngineStartStop
              << m_sendCmd.rightPumpGearSeq << m_sendCmd.rightPumpGear << m_sendCmd.rightReserve3
              << m_sendCmd.rightPumpThrottleSeq << m_sendCmd.rightPumpThrottle << m_sendCmd.rightReserve4
              << m_sendCmd.rightPumpRudderAngleSeq << m_sendCmd.rightPumpRudderAngle
              << m_sendCmd.reserve2 << m_sendCmd.reserve3 << m_sendCmd.reserve4 << m_sendCmd.reserve5;
    // 赋值CRC（小端）
    m_sendCmd.crc = qToLittleEndian(crc16((const uint8*)crcBuffer.data(), crcBuffer.size()));
}

// 发送m_sendCmd的内容到底层控制箱
bool BottomControlBox::sendCmd()
{
    //发送UDP数据报（目标：底层192.168.11.51:6500）后续从ini文件读取来更改此内容
    const QByteArray datagram((const char*)&m_sendCmd, sizeof(ControlCommand_BC));
    const qint64 sentLen = m_udpSocket->writeDatagram(datagram, QHostAddress(m_dstIp), m_dstPort);

    if(sentLen == datagram.size()) {
        return true;    //认为发送成功
    } else {
        return false;   //认为发送失败
    }
}

// 小端字节数组转主机字节序（无符号16位）
quint16 BottomControlBox::leToHost16(const quint8 *data)
{
    // 小端：低字节在前，高字节在后
    return static_cast<quint16>(data[0]) | (static_cast<quint16>(data[1]) << 8);
}

// 小端字节数组转主机字节序（有符号16位）
qint16 BottomControlBox::leToHost16S(const quint8 *data)
{
    return static_cast<qint16>(leToHost16(data));
}

// 打包帧数据
QByteArray BottomControlBox::packFrame()
{
    // 计算校验码：除去帧头、帧尾和校验码本身（原代码数组长度7但用了8个元素，已修正数组长度为8）
    unsigned char crcData[8];
    crcData[0] = m_frame.sourceNode;
    crcData[1] = m_frame.destNode;
    crcData[2] = m_frame.cmdType;
    crcData[3] = m_frame.ackFlag;
    crcData[4] = (m_frame.sequence >> 8) & 0xFF;  // 序号高8位
    crcData[5] = m_frame.sequence & 0xFF;         // 序号低8位
    crcData[6] = (m_frame.reserved2 >> 8) & 0xFF; // 预留高8位
    crcData[7] = m_frame.reserved2 & 0xFF;        // 预留低8位

    m_frame.crcCheck = crc16(crcData, 8);

    // 将结构体转换为字节数组
    QByteArray data;
    data.append((char*)&m_frame, sizeof(HeartbeatFrame));

    return data;
}

// 处理反馈信息（88字节报文解析）
void BottomControlBox::processFeedbackInfo(const QByteArray &strs)
{
    //判断ip的来源和目标是否对应上
    if(strs[4] != m_dstNode || strs[5] != m_srcNode) {
        emit sigError("来源ip或者目标ip不匹配");
        return;
    }

    //计算校验和，此处忽略不计（要求是可以不计算）

    const quint8 *dataPtr = reinterpret_cast<const quint8*>(strs.data()); // 字节数组转unsigned char指针，方便按偏移访问

    // 0-1字节：帧头+预留
    feedbackData.frameHead = dataPtr[0];
    feedbackData.reserve1 = dataPtr[1];

    // 2-3字节：数据长度（小端转主机序）
    feedbackData.dataLen = leToHost16(dataPtr + 2);

    // 4-7字节：节点信息+指令类型+确认标志（直接赋值，单字节无字节序问题）
    feedbackData.srcNode = dataPtr[4];
    feedbackData.dstNode = dataPtr[5];
    feedbackData.cmdType = dataPtr[6];
    feedbackData.confirmFlag = dataPtr[7];

    // 8-9字节：心跳（小端转主机序）
    feedbackData.heartbeat = leToHost16(dataPtr + 8);

    // 10-11字节：控制模式（小端转主机序）
    feedbackData.controlMode = leToHost16(dataPtr + 10);

    // 12-15字节：系统反馈1-4（单字节）
    feedbackData.sysFeedback1 = dataPtr[12];
    feedbackData.sysFeedback2 = dataPtr[13];
    feedbackData.sysFeedback3 = dataPtr[14];
    feedbackData.sysFeedback4 = dataPtr[15];

    // 16-19字节：油箱油量（小端转主机序）
    feedbackData.oilTank1 = leToHost16(dataPtr + 16) / 10;  //千分之转为百分之
    feedbackData.oilTank2 = leToHost16(dataPtr + 18) / 10;

    // 20-23字节：舵角值（有符号16位，小端转主机序）
    feedbackData.leftRudderAngle = leToHost16S(dataPtr + 20) / 10;
    feedbackData.rightRudderAngle = leToHost16S(dataPtr + 22) / 10;

    // 24-31字节：系统预留1-4（小端转主机序）
    feedbackData.sysReserve1 = leToHost16(dataPtr + 24);
    feedbackData.sysReserve2 = leToHost16(dataPtr + 26);
    feedbackData.sysReserve3 = leToHost16(dataPtr + 28);
    feedbackData.sysReserve4 = leToHost16(dataPtr + 30);

    // 32-57字节：左柴油机数据
    feedbackData.leftDieselGear = leToHost16(dataPtr + 32);
    feedbackData.leftDieselRpm = leToHost16(dataPtr + 34);  //不用更改，plc发过来的就是实际运行的
    feedbackData.leftDieselThrottle = leToHost16(dataPtr + 36);  //单位是0.4%,需后续处理

    // float类型：直接内存拷贝（协议为小端，float在内存中按字节序存储）
    memcpy(&feedbackData.leftDieselRunTime, dataPtr + 38, sizeof(float));

    feedbackData.leftDieselFuelRate = leToHost16(dataPtr + 42);
    feedbackData.leftDieselCoolTemp = dataPtr[44];
    feedbackData.leftDieselFuelTemp = dataPtr[45];
    memcpy(&feedbackData.leftDieselFaultCode, dataPtr + 46, sizeof(float));
    feedbackData.leftDieselOilPress = dataPtr[50];
    feedbackData.leftDieselIntakeTemp = dataPtr[51];
    feedbackData.leftDieselIgnVolt = leToHost16(dataPtr + 52);
    feedbackData.leftDieselStartStop = dataPtr[54];
    feedbackData.leftDieselRes1 = dataPtr[55];
    feedbackData.leftDieselRes2 = dataPtr[56];
    feedbackData.leftDieselRes3 = dataPtr[57];

    // 58-83字节：右柴油机数据
    feedbackData.rightDieselGear = leToHost16(dataPtr + 58);
    feedbackData.rightDieselRpm = leToHost16(dataPtr + 60);
    feedbackData.rightDieselThrottle = leToHost16(dataPtr + 62);
    memcpy(&feedbackData.rightDieselRunTime, dataPtr + 64, sizeof(float));
    feedbackData.rightDieselFuelRate = leToHost16(dataPtr + 68);
    feedbackData.rightDieselCoolTemp = dataPtr[70];
    feedbackData.rightDieselFuelTemp = dataPtr[71];

    // 右柴油机故障码：协议为Unsigned int（4字节），小端转主机序
    quint32 faultCode = static_cast<quint32>(dataPtr[72]) |
                       (static_cast<quint32>(dataPtr[73]) << 8) |
                       (static_cast<quint32>(dataPtr[74]) << 16) |
                       (static_cast<quint32>(dataPtr[75]) << 24);
    feedbackData.rightDieselFaultCode = faultCode;
    feedbackData.rightDieselOilPress = dataPtr[76];
    feedbackData.rightDieselIntakeTemp = dataPtr[77];
    feedbackData.rightDieselIgnVolt = leToHost16(dataPtr + 78);
    feedbackData.rightDieselStartStop = dataPtr[80];
    feedbackData.rightDieselRes1 = dataPtr[81];
    feedbackData.rightDieselRes2 = dataPtr[82];
    feedbackData.rightDieselRes3 = dataPtr[83];

    // 84-87字节：校验码+预留+帧尾
    feedbackData.crcCode = leToHost16(dataPtr + 84);
    feedbackData.frameTail = dataPtr[86];

    // 解析完成：发送信号传递结构体
    emit sigFeedbackParsed(feedbackData);
}

// 处理回令信息
void BottomControlBox::processCommandReply(const QByteArray &strs)
{
    const quint8* dataPtr = reinterpret_cast<const quint8*>(strs.data());

    //判断ip的来源和目标是否对应上
    if(dataPtr[4] != m_dstNode || dataPtr[5] != m_srcNode) {
        emit sigError("来源ip或者目标ip不匹配");
        return;
    }

    //计算校验和，此处忽略不计（要求是可以不计算）

    // 帧头、帧尾（直接赋值，单字节）
    m_reply.header = dataPtr[0];
    m_reply.reserve0 = dataPtr[1];
    // 数据长度（小端转主机序）
    m_reply.dataLen = leToHost16(dataPtr + 2);
    // 节点信息（单字节）
    m_reply.srcNode = dataPtr[4];
    m_reply.destNode = dataPtr[5];
    m_reply.cmdType = dataPtr[6];
    m_reply.confirmFlag = dataPtr[7];
    // 心跳号（小端转主机序，关键匹配项）
    m_reply.heartbeat = leToHost16(dataPtr + 8);
    // 预留2（小端转主机序）
    m_reply.reserve1 = leToHost16(dataPtr + 10);

    // 左柴油机启停回令（单字节）
    m_reply.leftEngineStartStopSeq = dataPtr[12];
    emit sigSuccess(QString("[receive] 左柴油机启停回令序号:%1").arg(m_reply.leftEngineStartStopSeq));
    // ********** 匹配待确认指令并删除（避免超时报警）**********
    CmdKey leftEngineStartStopSeKey(CmdType::LeftDieselStartStop, m_reply.leftEngineStartStopSeq);
    if (m_pendingCmds.contains(leftEngineStartStopSeKey)) {
        m_pendingCmds.remove(leftEngineStartStopSeKey);  // 确认收到回令，清除超时检测
    }

    m_reply.leftEngineStartStopResp = dataPtr[13];
    switch (m_reply.leftEngineStartStopResp) {  //判断收到的内容
    case 0x01:
        emit sigSuccess("[receive] 左柴油机启停回令:执行成功");
        break;
    case 0x02:
        emit sigError("[receive] 左柴油机启停回令:执行失败");
        break;
    case 0x03:
        emit sigError("[receive] 左柴油机启停回令:是非法指令");
        break;
    default:
        break;
    }

    // 左喷泵挡位回令
    m_reply.leftPumpGearSeq = dataPtr[14];
    emit sigSuccess(QString("[receive] 左喷泵挡位回令序号:%1").arg(m_reply.leftPumpGearSeq));
    CmdKey leftPumpGearKey(CmdType::LeftPumpGear, m_reply.leftPumpGearSeq);
    if (m_pendingCmds.contains(leftPumpGearKey)) {
        m_pendingCmds.remove(leftPumpGearKey);
    }

    m_reply.leftPumpGearResp = dataPtr[15];
    switch (m_reply.leftPumpGearResp) {  //判断收到的内容
    case 0x01:
        emit sigSuccess("[receive] 左喷泵挡位回令:执行成功");
        break;
    case 0x02:
        emit sigError("[receive] 左喷泵挡位回令:执行失败");
        break;
    case 0x03:
        emit sigError("[receive] 左喷泵挡位回令:非法指令");
        break;
    default:
        break;
    }

    // 左预留3
    m_reply.leftReserve3 = dataPtr[16];
    // 左喷泵油门回令
    m_reply.leftPumpThrottleSeq = dataPtr[17];
    emit sigSuccess(QString("[receive] 左喷泵油门回令序号:%1").arg(m_reply.leftPumpThrottleSeq));
    CmdKey lleftPumpThrottleSeqKey(CmdType::LeftPumpThrottle, m_reply.leftPumpThrottleSeq);
    if (m_pendingCmds.contains(lleftPumpThrottleSeqKey)) {
        m_pendingCmds.remove(lleftPumpThrottleSeqKey);
    }

    m_reply.leftPumpThrottleResp = dataPtr[18];
    switch (m_reply.leftPumpThrottleResp) {  //判断收到的内容
    case 0x01:
        emit sigSuccess("[receive] 左喷泵油门回令:执行成功");
        break;
    case 0x02:
        emit sigError("[receive] 左喷泵油门回令:执行失败");
        break;
    case 0x03:
        emit sigError("[receive] 左喷泵油门回令:非法指令");
        break;
    default:
        break;
    }

    // 左预留4
    m_reply.leftReserve4 = dataPtr[19];
    // 左喷泵舵角回令
    m_reply.leftPumpRudderAngleSeq = dataPtr[20];
    emit sigSuccess(QString("[receive] 左喷泵舵角回令序号:%1").arg(m_reply.leftPumpRudderAngleSeq));
    CmdKey leftPumpRudderAngleSeqKey(CmdType::LeftPumpRudderAngle, m_reply.leftPumpRudderAngleSeq);
    if (m_pendingCmds.contains(leftPumpRudderAngleSeqKey)) {
        m_pendingCmds.remove(leftPumpRudderAngleSeqKey);
    }

    m_reply.leftPumpRudderAngleResp = dataPtr[21];
    switch (m_reply.leftPumpRudderAngleResp) {  //判断收到的内容
    case 0x01:
        emit sigSuccess("[receive] 左喷泵舵角回令:执行成功");
        break;
    case 0x02:
        emit sigError("[receive] 左喷泵舵角回令:执行失败");
        break;
    case 0x03:
        emit sigError("[receive] 左喷泵舵角回令:非法指令");
        break;
    default:
        break;
    }

    // 右柴油机启停回令
    m_reply.rightEngineStartStopSeq = dataPtr[22];
    emit sigSuccess(QString("[receive] 右柴油机启停回令序号:%1").arg(m_reply.rightEngineStartStopSeq));
    CmdKey rightEngineStartStopSeqKey(CmdType::RightDieselStartStop, m_reply.rightEngineStartStopSeq);
    if (m_pendingCmds.contains(rightEngineStartStopSeqKey)) {
        m_pendingCmds.remove(rightEngineStartStopSeqKey);
    }

    m_reply.rightEngineStartStopResp = dataPtr[23];
    switch (m_reply.rightEngineStartStopResp) {  //判断收到的内容
    case 0x01:
        emit sigSuccess("[receive] 右柴油机启停指令执行成功");
        break;
    case 0x02:
        emit sigError("[receive] 右柴油机启停指令执行失败");
        break;
    case 0x03:
        emit sigError("[receive] 右柴油机启停指令是非法指令");
        break;
    default:
        break;
    }

    // 右喷泵挡位回令
    m_reply.rightPumpGearSeq = dataPtr[24];
    emit sigSuccess(QString("[receive] 右喷泵挡位回令序号:%1").arg(m_reply.rightPumpGearSeq));
    CmdKey rightPumpGearSeqKey(CmdType::RightPumpGear, m_reply.rightPumpGearSeq);
    if (m_pendingCmds.contains(rightPumpGearSeqKey)) {
        m_pendingCmds.remove(rightPumpGearSeqKey);
    }

    m_reply.rightPumpGearResp = dataPtr[25];
    switch (m_reply.rightPumpGearResp) {  //判断收到的内容
    case 0x01:
        emit sigSuccess("[receive] 右喷泵挡位回令:执行成功");
        break;
    case 0x02:
        emit sigError("[receive] 右喷泵挡位回令:执行失败");
        break;
    case 0x03:
        emit sigError("[receive] 右喷泵挡位回令:非法指令");
        break;
    default:
        break;
    }

    // 右预留3
    m_reply.rightReserve3 = dataPtr[26];
    // 右喷泵油门回令
    m_reply.rightPumpThrottleSeq = dataPtr[27];
    emit sigSuccess(QString("[receive] 右喷泵油门回令序号:%1").arg(m_reply.rightPumpThrottleSeq));
    CmdKey rightPumpThrottleSeqKey(CmdType::RightPumpThrottle, m_reply.rightPumpThrottleSeq);
    if (m_pendingCmds.contains(rightPumpThrottleSeqKey)) {
        m_pendingCmds.remove(rightPumpThrottleSeqKey);
    }

    m_reply.rightPumpThrottleResp = dataPtr[28];
    switch (m_reply.rightPumpThrottleResp) {  //判断收到的内容
    case 0x01:
        emit sigSuccess("[receive] 右喷泵油门回令:执行成功");
        break;
    case 0x02:
        emit sigError("[receive] 右喷泵油门回令:执行失败");
        break;
    case 0x03:
        emit sigError("[receive] 右喷泵油门回令:非法指令");
        break;
    default:
        break;
    }

    // 右预留4
    m_reply.rightReserve4 = dataPtr[29];
    // 右喷泵舵角回令
    m_reply.rightPumpRudderAngleSeq = dataPtr[30];
    emit sigSuccess(QString("[receive] 右喷泵舵角回令序号:%1").arg(m_reply.rightPumpRudderAngleSeq));
    CmdKey rightPumpRudderAngleSeqKey(CmdType::RightPumpRudderAngle, m_reply.rightPumpRudderAngleSeq);
    if (m_pendingCmds.contains(rightPumpRudderAngleSeqKey)) {
        m_pendingCmds.remove(rightPumpRudderAngleSeqKey);
    }

    m_reply.rightPumpRudderAngleResp = dataPtr[31];
    switch (m_reply.rightPumpRudderAngleResp) {  //判断收到的内容
    case 0x01:
        emit sigSuccess("[receive] 右喷泵舵角回令:执行成功");
        break;
    case 0x02:
        emit sigError("[receive] 右喷泵舵角回令:执行失败");
        break;
    case 0x03:
        emit sigError("[receive] 右喷泵舵角回令:非法指令");
        break;
    default:
        break;
    }

    // 预留3-5（小端转主机序）
    m_reply.reserve2 = leToHost16(dataPtr + 32);
    m_reply.reserve4 = leToHost16(dataPtr + 34);
    m_reply.reserve5 = leToHost16(dataPtr + 36);
    m_reply.reserve5 = leToHost16(dataPtr + 38);  // 原代码重复赋值reserve5，保持原样
    // CRC校验码（小端转主机序）
    m_reply.crc = leToHost16(dataPtr + 40);
    // 预留6、帧尾
    m_reply.tail = dataPtr[42];
}

// 接收消息处理，2种消息：回令、定时100ms反馈内容指令
void BottomControlBox::onReceive()
{
    while (m_udpSocket->hasPendingDatagrams()) {
        QNetworkDatagram datagram = m_udpSocket->receiveDatagram();
        QByteArray data = datagram.data();

        if(data.size() <= 4) return;

        //1、接收到数据后，判断帧头帧尾是否正确
        if(static_cast<quint8>(data[0]) == 0xFE && static_cast<quint8>(data.back()) == 0xFF) {
            //2、根据数据长度进入不同的解析（小端字节序）
            quint16 dataLength = static_cast<quint16>(static_cast<quint8>(data[2])) |
                              (static_cast<quint16>(static_cast<quint8>(data[3])) << 8);
            // 3、根据长度判断处理类型
            if (dataLength == 0x50) {
                // 处理反馈信息（长度80字节的情况）
                processFeedbackInfo(data);
            }
            else if (dataLength == 0x24) {
                // 处理回令信息（长度36字节的情况）
                processCommandReply(data);
            }
            else {
                // 处理未知长度的数据（可选）
                qWarning() << QString("收到未知长度的数据，长度: %1 字节").arg(dataLength);
            }
        }
    }
}

// 定时发送心跳包
void BottomControlBox::onSendHeartbeat()
{
    // 更新序号，循环计数
    m_sequence++;
    if (m_sequence > 65535) {
        m_sequence = 0;
    }

    m_frame.sequence = (m_sequence & 0x00FF) << 8 | (m_sequence & 0xFF00) >> 8;

    // 打包并发送帧数据
    QByteArray data = packFrame();
    int sendByte = m_udpSocket->writeDatagram(data, QHostAddress("255.255.255.255"), m_dstPort);
    if(m_isShowHeart) {
        if(sendByte == -1) {
            emit sigError("心跳发送失败");
        } else {
            emit sigSuccess("心跳发送成功");
        }
    }
}

// 超时检测
void BottomControlBox::onCheckTimeout()
{
    // 遍历待确认列表（用迭代器避免遍历中删除元素崩溃）
    QHash<CmdKey, QTime>::iterator it = m_pendingCmds.begin();
    while (it != m_pendingCmds.end()) {
        CmdKey key = it.key();
        QTime sendTime = it.value();
        // 计算发送到现在的时间差（ms）
        int elapsed = sendTime.elapsed();  // QTime::elapsed() 返回毫秒数

        if (elapsed > TIMEOUT_MS) {
            // ********** 超时：触发sigError报警**********
            CmdType cmdType = key.first;
            quint8 seq = key.second;
            QString cmdName;  // 指令名称（用于报警信息）

            // 匹配指令类型，生成易读的报警信息
            switch (cmdType) {
            case CmdType::LeftDieselStartStop: cmdName = "左柴油机启停指令"; break;
            case CmdType::LeftPumpGear: cmdName = "左喷泵挡位指令"; break;
            case CmdType::LeftPumpThrottle: cmdName = "左喷泵油门指令"; break;
            case CmdType::LeftPumpRudderAngle: cmdName = "左喷泵舵角指令"; break;
            case CmdType::RightDieselStartStop: cmdName = "右柴油机启停指令"; break;
            case CmdType::RightPumpGear: cmdName = "右喷泵挡位指令"; break;
            case CmdType::RightPumpThrottle: cmdName = "右喷泵油门指令"; break;
            case CmdType::RightPumpRudderAngle: cmdName = "右喷泵舵角指令"; break;
            default: cmdName = "未知指令"; break;
            }

            // 发送超时报警信号
            emit sigError(QString("[超时报警] %1（序号：%2）发送后%3秒未收到回令")
                         .arg(cmdName).arg(seq).arg(TIMEOUT_MS / 1000));

            // ********** 删除超时记录（避免重复报警）**********
            it = m_pendingCmds.erase(it);
        } else {
            // 未超时，继续遍历下一个
            ++it;
        }
    }
}
